﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Linq.Expressions;
using System.Data.Linq.Mapping;
using System.Data.Linq;
using SMS.Common.ServiceModel;
using System.IO;
using SMS.Common.Diagnostics;
using System.ComponentModel;
using SMS.Common.Search;

namespace SMS.Common.DataAccess
{
    public delegate EntityType GetOriginalMethod<EntityType>(EntityType entity);
    public class DataAccessBase<ContextType> : IDisposable where ContextType : DataContext, new()
    {
        private ContextType m_DataContext = null;
        private static StringWriter sm_LogWriter = null;
        private static StringBuilder sm_LogBuilder = null;
        public DataAccessBase()
        {
            m_DataContext = new ContextType();

            //LogInitialize();

            var conn = ConnectionString;
            if (!string.IsNullOrEmpty(conn))
            {
                m_DataContext.Connection.ConnectionString = conn;
            }
        }

        #region 成员属性

        private ContextType m_CurrentContext;
        /// <summary>
        /// 获取当前数据上下文
        /// </summary>
        public ContextType CurrentContext
        {
            get
            {
                //if (sm_CurrentContext == null) 
                m_CurrentContext = new DataAccessBase<ContextType>().DataContext;
                return m_CurrentContext;
            }
        }

        /// <summary>
        /// 获取数据上下文对象
        /// </summary>
        public virtual ContextType DataContext
        {
            get
            {
                return m_DataContext;
            }
        }

        private string m_DatabaseName;
        /// <summary>
        /// 数据库名称
        /// </summary>
        public virtual string DatabaseName
        {
            get
            {
                if (string.IsNullOrEmpty(m_DatabaseName) && m_DataContext != null)
                {
                    m_DatabaseName = m_DataContext.Mapping.DatabaseName;
                }
                return m_DatabaseName;
            }
            set
            {
                m_DatabaseName = value;
            }
        }

        private string m_ConnectionString;
        /// <summary>
        /// 获取或设置默认连接字符串
        /// </summary>
        public virtual string ConnectionString
        {
            get
            {
                if (string.IsNullOrEmpty(m_ConnectionString))
                {
                    m_ConnectionString = ConfigurationManager.AppSettings["ConnStr"];
                }
                var strCatalog = "Initial Catalog";
                if (!string.IsNullOrEmpty(m_ConnectionString) && !m_ConnectionString.Contains(strCatalog) && !string.IsNullOrEmpty(DatabaseName))
                {
                    m_ConnectionString += string.Format(";{0}={1}", strCatalog, DatabaseName);
                }
                return m_ConnectionString;
            }
            set
            {
                m_ConnectionString = value;
            }
        }

        #endregion

        #region SQL日志

        /// <summary>
        /// 日志初始化
        /// </summary>
        public void LogInitialize(DataContext dc)
        {
            sm_LogBuilder = new StringBuilder();
            sm_LogWriter = new StringWriter(sm_LogBuilder);
            dc.Log = sm_LogWriter;
        }

        /// <summary>
        /// 跟踪日志
        /// </summary>
        public void TrackingLog()
        {
            var logText = sm_LogBuilder.ToString();
            //sm_LogBuilder.Remove(0, logText.Length);
            if (!string.IsNullOrEmpty(logText)) SourceTracking.TraceInformation(logText);
        }

        /// <summary>
        /// 获取日志
        /// </summary>
        /// <returns></returns>
        public string GetLog()
        {
            if (sm_LogBuilder != null)
            {
                var logText = string.Format("{0}", sm_LogBuilder);
                //sm_LogBuilder.Remove(0, logText.Length);
                return logText;
            }
            return null;
        }

        #endregion

        #region IDisposable 成员

        public virtual void Dispose()
        {
            m_DataContext.Dispose();
        }

        #endregion

        #region 更新方法

        protected void Update<EntityType>(EntityType entity, GetOriginalMethod<EntityType> method) where EntityType : class
        {
            ITable table = m_DataContext.GetTable(entity.GetType());
            if (table != null)
            {
                if (table.GetOriginalEntityState(entity) != null)
                {
                    if (table.GetModifiedMembers(entity).Length > 0)
                    {
                        table.Context.SubmitChanges();
                    }
                }
                else
                {
                    MetaTable mt = table.Context.Mapping.GetTable(entity.GetType());
                    if (mt != null)
                    {
                        EntityType oEntity = method.Invoke(entity);
                        object objEntity = oEntity;
                        foreach (var item in mt.RowType.PersistentDataMembers)
                        {
                            if (item.IsPrimaryKey == false)
                            {
                                MetaAccessor ma = item.MemberAccessor;
                                object oValue = ma.GetBoxedValue(oEntity);
                                object nValue = ma.GetBoxedValue(entity);
                                if (object.Equals(oValue, nValue) == false)
                                {
                                    ma.SetBoxedValue(ref objEntity, nValue);
                                }
                            }
                        }
                        table.Context.SubmitChanges();
                    }
                    else
                    {
                        throw new InvalidOperationException("在数据上下文中找不到对应" + entity.GetType().FullName + "类型的映射信息");
                    }
                }
            }
            else
            {
                throw new InvalidOperationException("在数据上下文中找不到对应" + entity.GetType().FullName + "类型的表");
            }
        }

        #endregion

        #region 通用方法

        /// <summary>
        /// 搜索记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="condition"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public SearchResult<T> Search<T>(SearchCondition condition) where T : class
        {
            using (var dc = CurrentContext)
            {
                return SearchManager.Instance.Search<T>(dc, condition);
            }
        }

        /// <summary>
        /// 获取所有记录列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public List<T> GetAllList<T>() where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = true;
                return dc.GetTable<T>().ToList();
            }
        }

        /// <summary>
        ///　获取满足条件的记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual List<T> GetEntityList<T>(Expression<Func<T, bool>> expression) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = true;
                return dc.GetTable<T>().Where(expression).ToList();
            }
        }

        /// <summary>
        /// 获取满足条件的记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public virtual List<T> GetEntityList<T>(string predicate, params object[] values) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                return dc.GetTable<T>().Where(predicate, values).ToList<T>();
            }
        }

        /// <summary>
        /// 获取满足条件的唯一记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual T GetSingleEntity<T>(Expression<Func<T, bool>> expression) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = true;
                return dc.GetTable<T>().SingleOrDefault(expression);
            }
        }

        /// <summary>
        /// 获取满足条件的首条记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        public virtual T GetFirstEntity<T>(Expression<Func<T, bool>> expression) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = true;
                return dc.GetTable<T>().FirstOrDefault(expression);
            }
        }

        /// <summary>
        /// 获取满足条件的最大记录值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="S"></typeparam>
        /// <param name="expression"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public virtual S GetMaxEntityValue<T, S>(Expression<Func<T, bool>> expression, Expression<Func<T, S>> selector)
            where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                var entities = dc.GetTable<T>().Where(expression);
                if (entities == null || entities.Count() == 0) return default(S);
                return entities.Max<T, S>(selector);
            }
        }

        /// <summary>
        /// 新增记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        [DataObjectMethod(DataObjectMethodType.Insert)]
        public virtual int AddEntity<T>(T entity) where T : class
        {
            if (entity == null) return 0;
            using (var dc = CurrentContext)
            {
                dc.GetTable<T>().InsertOnSubmit(entity);
                dc.SubmitChanges();
                return 1;
            }
        }

        /// <summary>
        /// 新增记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entities"></param>
        [DataObjectMethod(DataObjectMethodType.Insert)]
        public virtual int AddEntities<T>(T[] entities) where T : class
        {
            if (entities == null || entities.Length == 0) return 0;
            using (var dc = CurrentContext)
            {
                var nCount = 0;
                foreach (var entity in entities)
                {
                    dc.GetTable<T>().InsertOnSubmit(entity);
                    nCount++;
                }
                if (nCount > 0) dc.SubmitChanges();
                return nCount;
            }
        }

        /// <summary>
        /// 更新记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        [DataObjectMethod(DataObjectMethodType.Update)]
        public virtual int UpdateEntity<T>(T entity) where T : class
        {
            if (entity == null) return 0;
            using (var dc = CurrentContext)
            {
                dc.GetTable<T>().Attach(entity, true);
                dc.SubmitChanges();
                return 1;
            }
        }

        /// <summary>
        /// 更新记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entities"></param>
        [DataObjectMethod(DataObjectMethodType.Update)]
        public virtual int UpdateEntities<T>(T[] entities) where T : class
        {
            if (entities == null || entities.Length == 0) return 0;
            using (var dc = CurrentContext)
            {
                var nCount = 0;
                foreach (var entity in entities)
                {
                    dc.GetTable<T>().Attach(entity, true);
                    nCount++;
                }
                if (nCount > 0) dc.SubmitChanges();
                return nCount;
            }
        }

        /// <summary>
        /// 删除记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        public virtual int DeleteEntity<T>(Expression<Func<T, bool>> expression) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;

                var entities = dc.GetTable<T>().Where(expression).ToList<T>();
                var nCount = 0;
                if (entities == null)
                {
                    return 0;
                }
                else
                {
                    nCount = entities.Count();
                }
                if (nCount > 0)
                {
                    dc.GetTable<T>().DeleteAllOnSubmit<T>(entities);
                    dc.SubmitChanges();
                }
                return nCount;
            }
        }

        /// <summary>
        /// 删除满足条件的记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Delete)]
        public virtual int DeleteEntitiy<T>(string predicate, params object[] values) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                var entities = dc.GetTable<T>().Where(predicate, values);
                var nCount = 0;
                if (entities == null)
                {
                    return 0;
                }
                else
                {
                    nCount = entities.Count();
                }
                if (nCount > 0)
                {
                    dc.GetTable<T>().DeleteAllOnSubmit<T>(entities);
                    dc.SubmitChanges();
                }
                return nCount;
            }
        }

        /// <summary>
        /// 批量删除记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entities"></param>
        [DataObjectMethod(DataObjectMethodType.Delete)]
        public virtual int DeleteEntities<T>(IEnumerable<T> entities) where T : class
        {
            if (entities == null || entities.Count() == 0) return 0;
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                foreach (var item in entities)
                {
                    dc.GetTable<T>().Attach(item, true);
                }
                dc.GetTable<T>().DeleteAllOnSubmit<T>(entities);
                dc.SubmitChanges();
                return entities.Count();
            }
        }

        /// <summary>
        /// 判断是否存在满足条件的记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public virtual bool ExistEntity<T>(Expression<Func<T, bool>> expression) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                return dc.GetTable<T>().Count(expression) > 0;
            }
        }

        /// <summary>
        /// 判断是否存在满足条件的记录
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public virtual bool ExistEntity<T>(string predicate, params object[] values) where T : class
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                return dc.GetTable<T>().Where(predicate, values).Count() > 0;
            }
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="command"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public virtual int ExecuteCommand(string command, params string[] args)
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                return dc.ExecuteCommand(command, args);
            }
        }

        /// <summary>
        /// 执行查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select)]
        public virtual List<T> ExecuteQuery<T>(string query, params string[] args)
        {
            using (var dc = CurrentContext)
            {
                dc.ObjectTrackingEnabled = false;
                return ((IEnumerable<T>)dc.ExecuteQuery(typeof(T), query, args)).ToList();
            }
        }

        #endregion
    }
}
